/** @jsxImportSource @emotion/react */
import {jsx,css} from "@emotion/react";
import * as React from "react";
// import { Text } from "./Text";
// import { CloseButton } from "./IconButton";
import { useTransition, animated } from "@react-spring/web";
// import { useTheme } from "./Theme/Providers";


import {
  useFloating,
  useClick,
  useDismiss,
  useRole,
  useInteractions,
  FloatingPortal,
  FloatingFocusManager,
  FloatingOverlay,
  useId
} from "@floating-ui/react";
import { mergeRefs } from "react-merge-refs";
// import {breakpoints} from "./Theme/breakpoints";
import {CSSProperties} from "react";

import {
    useTheme, Text, LayerRefComp,Touchable,CloseButton
} from "customize-easy-ui-component";


interface DialogOptions {
    //非受控方式的初始值
  initialOpen?: boolean;
  //注入控制器的方式：实时取值
  open?: boolean;
  onOpenChange?: (open: boolean) => void;
  //是不是必须手动关闭，点击外部区域的不会自动关闭;  true=不会自动关闭！；
  modal?: boolean;
}

export function useDialog({
                            initialOpen = false,
                            modal=true,
                            open: controlledOpen,
                            onOpenChange: setControlledOpen
                          }: DialogOptions = {}) {
  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(initialOpen);
  const [labelId, setLabelId] = React.useState<string | undefined>();
  const [descriptionId, setDescriptionId] = React.useState<
      string | undefined
      >();

  const open = controlledOpen ?? uncontrolledOpen;
  const setOpen = setControlledOpen ?? setUncontrolledOpen;

  const data = useFloating({
    open,
    onOpenChange: setOpen
  });

  const context = data.context;

  const click = useClick(context, {
    enabled: controlledOpen == null
  });
  //确保不会因为点击对话框区域之外立刻关闭地：//modal={state.modal}
  const dismiss = useDismiss(context, {
      outsidePressEvent: "mousedown",
      outsidePress:  !modal,
  });
  const role = useRole(context);

  const interactions = useInteractions([click, dismiss, role]);

  return React.useMemo(
      () => ({
        open,
        setOpen,
        ...interactions,
        ...data,
        labelId,
        descriptionId,
        setLabelId,
        setDescriptionId,
        modal,
      }),
      [open, setOpen, interactions, data, labelId, descriptionId]
  );
}

type ContextType =
    | (ReturnType<typeof useDialog> & {
  setLabelId: React.Dispatch<React.SetStateAction<string | undefined>>;
  setDescriptionId: React.Dispatch<
      React.SetStateAction<string | undefined>
      >;
})
    | null;

const DialogContext = React.createContext<ContextType>(null);

export const useDialogState = () => {
  const context = React.useContext(DialogContext);

  if (context == null) {
    throw new Error("Dialog components must be wrapped in <Dialog />");
  }

  return context;
};

export function Dialog({
                         children,
                         ...options
                       }: {
  children: React.ReactNode;
} & DialogOptions) {
  // This can accept any props as options, e.g. `placement`,
  // or other positioning options.
  const dialog = useDialog(options);
  return (
      <DialogContext.Provider value={dialog}>{children}</DialogContext.Provider>
  );
}

interface DialogTriggerProps {
  children: React.ReactNode;
  asChild?: boolean;
}

/*自带控制器模式；
可以用<Dialog open={open} onOpenChange={setOpen}>直接代替<DialogTrigger>
* */
export const DialogTrigger = React.forwardRef<
    HTMLElement,
    React.HTMLProps<HTMLElement> & DialogTriggerProps
    >(function DialogTrigger({ children, asChild = false, ...props }, propRef) {
  const state = useDialogState();
  const childrenRef = (children as any).ref;

  const ref = React.useMemo(
      () => mergeRefs([state.reference, propRef, childrenRef]),
      [state.reference, propRef, childrenRef]
  );

  // `asChild` allows the user to pass any element as the anchor
  if (asChild && React.isValidElement(children)) {
    return React.cloneElement(
        children,
        state.getReferenceProps({
          ref,
          ...props,
          ...children.props,
          "data-state": state.open ? "open" : "closed"
        })
    );
  }

  return (
      <button
          ref={ref}
          // The user can style the trigger based on the state
          data-state={state.open ? "open" : "closed"}
          {...state.getReferenceProps(props)}
      >
        {children}
      </button>
  );
});


interface OverlayOptions {
    //OverLay最上一级的样式; 【极特殊情形】地图不要Y轴线的滚动了。地图全屏也不要任何滚动条。
    layStyle?: CSSProperties;
}

/*对话框主体部分：
全屏幕对话框比如地图那样的，看着和独立有路由器URL赋能的主页面很相似的，就是多了个关闭"X"按钮和标题。
* */
export const DialogContent = React.forwardRef<
    HTMLDivElement,
    React.HTMLProps<HTMLDivElement> & OverlayOptions
    >(function DialogContent({layStyle, ...props}, propRef) {
  const state = useDialogState();

  const ref = React.useMemo(() => mergeRefs([state.floating, propRef]), [
    state.floating,
    propRef
  ]);

    const theme = useTheme();

    //底下的<div "DialogIn" style={{似乎比css={[优先吗，还是因为...props.style注入的更优先的缘故。
  return (
      <FloatingPortal>
        {state.open && (
            <FloatingOverlay className="Dialog-overlay" lockScroll
                     style={{
                         zIndex: theme.zIndices.modal,
                         display: 'flex',
                         overflow: 'unset',     //在FloatingOverlay内部默认有了
                         overflowX: 'hidden',
                         ...layStyle,
                     }}
            >
              <FloatingFocusManager context={state.context}  modal={state.modal}
                     closeOnFocusOut={false}  guards={true}  returnFocus={true}
              >
                <div  className="DialogContent"
                    ref={ref}
                    aria-labelledby={state.labelId}
                    aria-describedby={state.descriptionId}
                    {...state.getFloatingProps(props)}
                    style={{
                          display: 'flex',
                          margin: 'auto',
                          overflowY: 'auto',
                          //这上[theme.mediaQueries.md]: {}的会报错! width放在style={{里导致无法从外面注入到这底下的css={{来覆盖！
                      }}
                >
                    <div  className="DialogIn"
                          style={{
                              backgroundColor: 'white',
                              minHeight: "30vh",
                          }}
                          css={
                              {
                                  width: "100%",
                                  border: '2px solid #ddd',
                                  borderRadius: theme.radii.sm,
                                  boxShadow: theme.shadows.sm,
                                  padding: '4px',
                                  [theme.mediaQueries.md]: {
                                      margin: '1rem',
                                      border: '3px solid #ddd',
                                      padding: '8px',
                                      maxWidth: "760px",
                                      boxShadow: theme.shadows.md,
                                      borderRadius: theme.radii.md,
                                  },
                                  [theme.mediaQueries.lg]: {
                                      maxWidth: "990px",
                                      boxShadow: theme.shadows["lg"],
                                      borderRadius: theme.radii.lg,
                                  },
                                  "@media print": {
                                      boxShadow: 'unset',
                                  },
                                  ...props.style,
                              }
                          }
                    >
                        {props.children}
                    </div>
                </div>
              </FloatingFocusManager>
            </FloatingOverlay>
        )}
      </FloatingPortal>
  );
});


interface DialogHeadingOptions {
    //标题文本替换成组件
    asChild?: boolean;
    //右顶头"X"关闭按钮样式
    closeStyle?: CSSProperties;
}
/*
这底下添加tabIndex={0}才能消除了此毛病：内容超过一个屏幕高度的话，就感觉古怪，直接跳到最后，无法正面显示头部，还要滚动。
* */
export const DialogHeading = React.forwardRef<
    HTMLHeadingElement,
    React.HTMLProps<HTMLHeadingElement> & DialogHeadingOptions
    >(function DialogHeading(
        { children,
  asChild = false,closeStyle, ...props }, ref) {
  const { setLabelId, setOpen } = useDialogState();
  const id = useId();

  // Only sets `aria-labelledby` on the Dialog root element
  // if this component is mounted inside it.
  React.useLayoutEffect(() => {
    setLabelId(id);
    return () => setLabelId(undefined);
  }, [id, setLabelId]);

    //支持更自由的自定义头部：
    const textComp= (asChild && React.isValidElement(children) ) ?
            React.cloneElement(
                children,
                {
                    ...children.props,
                }
            )
        :
            <Text wrap={true} variant="h5">
                {children}
            </Text>;

    //似乎只能style={{ 不能改为css={{;
  return (
      <div  ref={ref} id={id} tabIndex={-1}  autoFocus={false}
            style={{
                justifyContent: 'space-between',
                display: 'flex',
                // ...props.style,
            }}
          {...props}
      >
          {textComp}
          <CloseButton
              style={{
                ...closeStyle,
              }}
              onClick={() => setOpen(false)}
          />
      </div>
  );
});


export const DialogDescription = React.forwardRef<
    HTMLParagraphElement,
    React.HTMLProps<HTMLParagraphElement>
    >(function DialogDescription({ children, ...props }, ref) {
  const { setDescriptionId } = useDialogState();
  const id = useId();

  // Only sets `aria-describedby` on the Dialog root element
  // if this component is mounted inside it.
  React.useLayoutEffect(() => {
    setDescriptionId(id);
    return () => setDescriptionId(undefined);
  }, [id, setDescriptionId]);

  return (
      <div {...props} ref={ref} id={id}>
        {children}
      </div>
  );
});


export const DialogClose = React.forwardRef<
    HTMLButtonElement,
    React.ButtonHTMLAttributes<HTMLButtonElement>
    >(function DialogClose({ children, ...props }, ref) {
  const state = useDialogState();
  return (
      <button {...props} ref={ref}
              onClick={() => state.setOpen(false)}
          css={{
              marginTop: '0.5rem',
              marginLeft: '1rem',
          }}
      >
        {children}
      </button>
  );
});

